package com.sky.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.WebSocketServer.WebSocketServer;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.properties.BaiduProperties;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.OrderService;
import com.sky.utils.HttpClientUtil;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.lang.model.element.Name;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户下单业务实现
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private BaiduProperties baiduProperties;
    @Autowired
    private WebSocketServer webSocketServer;
    /**
     * 用户下单
     * @param ordersSubmitDTO
     * @return
     */
    @Transactional
    public OrderSubmitVO addOrder(OrdersSubmitDTO ordersSubmitDTO) {
        Long currentUser = BaseContext.getCurrentId();
        //校验购物车数据
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.selectShoppingCartByUserId(currentUser);
        if (CollUtil.isEmpty(shoppingCartList)){
            throw new OrderBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //校验地址
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if (ObjectUtil.isNull(addressBook)){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        //获取用户地址信息
        String userAddress = StrUtil.join("", addressBook.getProvinceName(), addressBook.getCityName(),
                addressBook.getDistrictName(), addressBook.getDetail());
        //校验用户地址与商家距离
        if(checkLocation(userAddress)){
            log.info("用户地址在配送范围内");

            //向订单表插入一条数据
            Orders orders = new Orders();
            BeanUtil.copyProperties(ordersSubmitDTO,orders);
            orders.setNumber(Convert.toStr(System.currentTimeMillis()));
            orders.setStatus(Orders.PENDING_PAYMENT);
            orders.setUserId(currentUser);
            //orders.setAddressBookId(addressBook.getId());
            orders.setOrderTime(LocalDateTime.now());
            orders.setPayStatus(Orders.UN_PAID);
            orders.setPhone(addressBook.getPhone());
            orders.setAddress(addressBook.getDetail());
            orders.setConsignee(addressBook.getConsignee());
            orderMapper.insertOrder(orders);

            //向订单细节表插入N条数据
            List<OrderDetail> orderDetailList = BeanUtil.copyToList(shoppingCartList, OrderDetail.class);
            log.info("从购物车中拷贝的订单细节数据：{}",orderDetailList);
            //给订单细节对象设置订单id
            orderDetailList.forEach(orderDetail -> orderDetail.setOrderId(orders.getId()));
            orderDetailMapper.BatchInsert(orderDetailList);

            //清空购物车
            shoppingCartMapper.deleteShoppingCart(currentUser);

            return OrderSubmitVO.builder()
                    .orderNumber(orders.getNumber())
                    .orderAmount(orders.getAmount())
                    .orderTime(orders.getOrderTime())
                    .build();




        }else {
            throw new OrderBusinessException(MessageConstant.EXCEEDING_DELIVERY_DISTANCE);
        }
    }

    /**

     * 订单支付
     *

     * @param ordersPaymentDTO

     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);
        log.info("当前用户为：{}",user);
        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                ordersPaymentDTO.getOrderNumber(), //商户订单号
                new BigDecimal(0.01), //支付金额，单位 元
                "苍穹外卖订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        return vo;
    }

    /**

     * 支付成功，修改订单状态
     *

     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单号查询当前用户的订单
        Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setPayStatus(Orders.PAID);
        orders.setCheckoutTime(LocalDateTime.now());
        orderMapper.update(orders);

        //使用 webSocket，来单提醒
        cn.hutool.json.JSONObject jsonObject = JSONUtil.createObj();
        jsonObject.append("type",1);
        jsonObject.append("orderId",orders.getId());
        jsonObject.append("content", "订单号：" + outTradeNo);
        webSocketServer.sendToAllClient(JSONUtil.toJsonStr(jsonObject));
    }

    /**
     * C端-分页查询历史订单
     * @param
     *
     *
     * @return
     */
    public PageResult getHistoryOrders(OrdersPageQueryDTO ordersPageQueryDTO) {
        Page<OrderVO> page = PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        orderMapper.SelectHistoryOrdersByPage(ordersPageQueryDTO);
        //封装OrderDetail
        for (OrderVO vo: page.getResult()) {
            List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetailByorderId(vo.getId());
            vo.setOrderDetailList(orderDetails);
        }
        return new PageResult(page.getTotal(),page);
    }

    /**
     * C端-根据订单id查询订单
     * @param id
     * @return
     */
    public OrderVO getOrderById(Long id) {
        Orders orders = orderMapper.getOrderById(id);
        List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetailByorderId(id);
        OrderVO orderVO = new OrderVO();
        BeanUtil.copyProperties(orders,orderVO);
        orderVO.setOrderDetailList(orderDetails);
        return orderVO;
    }

    /**
     * C端-根据订单id取消订单
     * @param id
     */
    public void CancelOrderById(Long id) {
        //判断订单状态
        //1、如果待支付，更新订单状态为6
        Orders order = orderMapper.getOrderById(id);
        if (Orders.PENDING_PAYMENT.equals(order.getStatus())){
            order.setStatus(Orders.CANCELLED);
            order.setCancelTime(LocalDateTime.now());
            orderMapper.update(order);
        }
        //2、如果已支付，商家待接单，更新订单状态为6并退款
        if ((Orders.PAID.equals(order.getPayStatus())) && (Orders.TO_BE_CONFIRMED.equals(order.getStatus()))){
            order.setStatus(Orders.CANCELLED);
            order.setCancelTime(LocalDateTime.now());
            orderMapper.update(order);
            //退款给用户
        }
        //3、如果商家已结单，抛异常
        if (Orders.CONFIRMED.equals(order.getStatus())){
            throw new OrderBusinessException(MessageConstant.ORDER_CANCLE_EXCEPTION);
        }
    }


    /**
     * C端-再来一单
     * @param id
     */
    public void OneMoreOrder(Long id) {
        //根据订单id查询订单明细
        List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetailByorderId(id);
        //将订单明细重新加入购物车
        orderDetails.forEach(orderDetail -> {
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtil.copyProperties(orderDetail,shoppingCart);
            shoppingCart.setUserId(BaseContext.getCurrentId());
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCartMapper.insertShoppingCart(shoppingCart);
        });
    }

    /**
     * 订单分页条件查询
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult PageOrder(OrdersPageQueryDTO ordersPageQueryDTO) {
        Page<OrderVO> page = PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        orderMapper.SelectHistoryOrdersByPage(ordersPageQueryDTO);
        //封装OrderDetail
        for (OrderVO vo: page.getResult()) {
            List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetailByorderId(vo.getId());
            vo.setOrderDetailList(orderDetails);
            //封装菜品名称
            String[] array = orderDetails.stream().map(orderDetail -> {
                String name = orderDetail.getName();
                Integer number = orderDetail.getNumber();
                return StrUtil.join("*", name, number.toString());
            }).toArray(String[]::new);
            log.info("拼的菜品字符串数组为：{}",array);
            String rs = StrUtil.join(";", array);
            log.info("拼的菜品字符串为：{}",rs);
            vo.setOrderDishes(rs);
        }
        return new PageResult(page.getTotal(),page);
    }

    /**
     * 根据订单id查看订单详情
     * @param id
     * @return
     */
    public OrderVO getOrderDetailById(Long id) {
        Orders order = orderMapper.getOrderById(id);
        List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetailByorderId(id);
        OrderVO orderVO = new OrderVO();
        BeanUtil.copyProperties(order,orderVO);
        orderVO.setOrderDetailList(orderDetails);
        /*//封装菜品名称
        String[] array = orderDetails.stream().map(orderDetail -> {
            String name = orderDetail.getName();
            Integer number = orderDetail.getNumber();
            return StrUtil.join("*", name, number.toString());
        }).toArray(String[]::new);
        log.info("拼的菜品字符串数组为：{}",array);
        String rs = StrUtil.join(";", array);
        log.info("拼的菜品字符串为：{}",rs);
        orderVO.setOrderDishes(rs);*/
        return orderVO;
    }

    /**
     * 获取各个状态订单数量
     * @return
     */
    public OrderStatisticsVO getOrderCount() {
          //根据订单状态统计数量    select count(0) from orders where status = 2
         Integer toBeConfirmed = orderMapper.getOrderByStatus(Orders.TO_BE_CONFIRMED);
         log.info("待接单数：{}",toBeConfirmed);
         Integer confirmed = orderMapper.getOrderByStatus(Orders.CONFIRMED);
        log.info("待派送数：{}",confirmed);
        Integer deliveryInProgress = orderMapper.getOrderByStatus(Orders.DELIVERY_IN_PROGRESS);
        log.info("派送中数：{}",deliveryInProgress);
        return OrderStatisticsVO.builder()
                .confirmed(confirmed)
                .toBeConfirmed(toBeConfirmed)
                .deliveryInProgress(deliveryInProgress)
                .build();
    }

    /**
     * 接单
     * @param
     */
    public void confirmOrder(OrdersConfirmDTO ordersConfirmDTO) {
        Orders order = orderMapper.getOrderById(ordersConfirmDTO.getId());
        //校验订单
        if (ObjectUtil.isNull(order)){
            //订单不存在
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!Orders.TO_BE_CONFIRMED.equals(order.getStatus())){
            //订单状态不是待接单
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }else {
            //更新为已接单
            order.setStatus(Orders.CONFIRMED);
            orderMapper.update(order);
        }
    }


    /**
     * 拒单
     * @param ordersRejectionDTO
     */
    public void rejectionOrder(OrdersRejectionDTO ordersRejectionDTO) {
        Orders order = orderMapper.getOrderById(ordersRejectionDTO.getId());
        //校验订单
        if (ObjectUtil.isNull(order)){
            //订单不存在
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!Orders.TO_BE_CONFIRMED.equals(order.getStatus())){
            //订单状态不是待接单
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }else {
            //更新为已取消
            order.setStatus(Orders.CANCELLED);
            order.setRejectionReason(ordersRejectionDTO.getRejectionReason());
            orderMapper.update(order);
        }
    }


    /**
     * 取消订单
     * @param ordersCancelDTO
     */
    public void cancelOrder(OrdersCancelDTO ordersCancelDTO) {
        Orders order = orderMapper.getOrderById(ordersCancelDTO.getId());
        //校验订单
        if (ObjectUtil.isNull(order)){
            //订单不存在
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        //校验订单付款状态
        if (Orders.UN_PAID.equals(order.getPayStatus())){
            //未付款
            order.setStatus(Orders.CANCELLED);
            order.setCancelReason(ordersCancelDTO.getCancelReason());
            order.setCancelTime(LocalDateTime.now());
            orderMapper.update(order);
        }
        if (Orders.PAID.equals(order.getPayStatus())){
            //已支付
            //退款
            order.setStatus(Orders.CANCELLED);
            order.setCancelReason(ordersCancelDTO.getCancelReason());
            order.setCancelTime(LocalDateTime.now());
            orderMapper.update(order);
        }
    }

    /**
     * 派送订单
     * @param id
     */
    public void deliveryOrder(Long id) {
        Orders order = orderMapper.getOrderById(id);
        //校验订单
        if (ObjectUtil.isNull(order)){
            //订单不存在
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!Orders.CONFIRMED.equals(order.getStatus())){
            //订单状态不是已接单
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }else {
            //更新为派送中
            order.setStatus(Orders.DELIVERY_IN_PROGRESS);
            orderMapper.update(order);
        }
    }


    /**
     * 完成订单
     * @param id
     */
    public void completeOrder(Long id) {
        Orders order = orderMapper.getOrderById(id);
        //校验订单
        if (ObjectUtil.isNull(order)){
            //订单不存在
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!Orders.DELIVERY_IN_PROGRESS.equals(order.getStatus())){
            //订单状态不是派送中
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }else {
            //更新为已完成
            order.setStatus(Orders.COMPLETED);
            orderMapper.update(order);
        }
    }

    public boolean checkLocation(String userAddress){
        //1、获取商家位置经纬度
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("address",baiduProperties.getAddress());
        paramMap.put("output","json");
        paramMap.put("ak",baiduProperties.getAk());
        log.info("商家地址查询参数：{}",paramMap);
        String JsonStr = HttpClientUtil.doGet(BaiduProperties.URL, paramMap);
        JSONObject jsonObject = JSONObject.parseObject(JsonStr);
        log.info("商家地址返回数据：{}",jsonObject);
        JSONObject ShopLocation = jsonObject.getJSONObject("result").getJSONObject("location");
        log.info("商家地址经纬度：{}",ShopLocation);
        double lat = ShopLocation.getBigDecimal("lat").doubleValue();
        lat = NumberUtil.round(lat, 6).doubleValue();
        log.info("商家地址纬度--->{}",lat);
        double lng = ShopLocation.getBigDecimal("lng").doubleValue();
        lng = NumberUtil.round(lng, 6).doubleValue();
        log.info("商家地址经度--->{}",lng);


        //2、获取用户地址经纬度
        paramMap.put("address",userAddress);
        log.info("用户地址查询参数：{}",paramMap);
        String userJsonStr = HttpClientUtil.doGet(BaiduProperties.URL, paramMap);
        JSONObject jsonObject2 = JSONObject.parseObject(userJsonStr);
        log.info("用户地址返回数据：{}",jsonObject2);
        JSONObject userLocation = jsonObject2.getJSONObject("result").getJSONObject("location");
        log.info("用户地址经纬度：{}",userLocation);
        double lat2 = userLocation.getBigDecimal("lat").doubleValue();
        lat2 = NumberUtil.round(lat2, 6).doubleValue();
        log.info("用户地址纬度--->{}",lat2);
        double lng2 = userLocation.getBigDecimal("lng").doubleValue();
        lng2 = NumberUtil.round(lng2, 6).doubleValue();
        log.info("用户地址经度--->{}",lng2);


        //3、校验距离
        Map<String, String> paramMap2 = new HashMap<>();
        paramMap2.put("ak", baiduProperties.getAk());
        paramMap2.put("origin",lat + "," +lng);
        paramMap2.put("destination",lat2 + "," +lng2);
        log.info("距离校验参数：{}",paramMap2);
        String rsJsonStr = HttpClientUtil.doGet(BaiduProperties.CHECK_URL, paramMap2);
        JSONObject rsJsonObject = JSONObject.parseObject(rsJsonStr);
        log.info("距离结果：{}",rsJsonObject);
        JSONArray routes = rsJsonObject.getJSONObject("result").getJSONArray("routes");
        JSONObject route = routes.getJSONObject(0);
        log.info("routes--->{}",route);
        Integer distance = route.getInteger("distance");
        log.info("距离--->{}",distance);

        if (distance > 5000){
            return false;
        }
        return true;
    }


    /**
     * C端-客户催单
     * @param id
     */
    public void ReminderOrder(Long id) {
        Orders order = orderMapper.getOrderById(id);
        if (ObjectUtil.isNull(order)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        // 调webSocket发送催单消息给商家
        cn.hutool.json.JSONObject jsonObject = JSONUtil.createObj();
        jsonObject.append("type",2);
        jsonObject.append("orderId",order.getId());
        jsonObject.append("content","订单号：" + order.getNumber());
        webSocketServer.sendToAllClient(JSONUtil.toJsonStr(jsonObject));
    }
}
